package top.xia17.plugins.fast.common.utils;

import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.ZipUtil;
import jakarta.validation.constraints.NotBlank;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.multipart.MultipartFile;
import top.xia17.plugins.fast.common.exceptions.BadRequestException;
import top.xia17.plugins.fast.common.model.Back;

import java.io.*;
import java.util.function.Function;

/**
 * 文件工具
 * @author xia17
 * @date 2020/12/28 14:18
 */
@Slf4j
public class FileUtil {


    /**
     * 将MultipartFile文件保存到本地
     * @param file 上传的文件
     * @param filePath 保存到本地的入径
     * @return 是否保存成功
     */
    public static boolean save(MultipartFile file,String filePath){
        if (StrUtil.isBlank(filePath)){
            log.error("保存文件时文件地址为空");
            return false;
        }
        File dest = new File(filePath);
        if (dest.exists()){
            log.error("保存文件时文件已存在");
            return false;
        }
        if (!dest.getParentFile().exists()){
            if (!dest.getParentFile().mkdirs()){
                log.error("保存文件时文件目录创建失败");
                return false;
            }
        }
        try {
            file.transferTo(dest);
        } catch (IOException e) {
            log.error("保存文件时发生异常",e);
            return false;
        }
        return true;
    }

    /**
     * 将ByteArrayOutputStream转换成文件并保存至指定入径
     * @param outputStream /
     * @param filePath 入径
     */
    public static void save(ByteArrayOutputStream outputStream,String filePath){
        // 保存至临时文件夹
        try(FileOutputStream fileOutputStream = new FileOutputStream(filePath)) {
            fileOutputStream.write(outputStream.toByteArray());
        } catch (IOException e) {
            throw new BadRequestException("将文件保存至本地" + filePath + "发生异常");
        }
    }

    /**
     * 获取文件后缀名 包括点
     * lg： aa.aa.px 结果是 .px
     * @param fileName 文件名
     * @return /
     */
    public static String getFileSuffix(String fileName){
        if (StrUtil.isBlank(fileName)){
            return "";
        }
        int lastIndexOf = fileName.lastIndexOf(".");
        if (lastIndexOf < 0){
            return "";
        }
        //获取文件的后缀名 .jpg
        return fileName.substring(lastIndexOf);
    }

    /**
     * 创建目录
     * @param path 目录路径
     */
    public static void mkdirs(@NotBlank String path) {
        File file = new File(path);
        if (file.exists()){
            log.warn("{}目录已经存在无需创建",path);
            return;
        }
        if (file.mkdirs()){
            log.info("{}目录创建成功",path);
        }else {
            log.error("{}目录创建失败",path);
        }
    }

    /**
     * 文件转ByteArrayOutputStream
     * @param path 文件路径
     * @return /
     */
    public static ByteArrayOutputStream fileToByteArrayOutputStream(String path){
        File file = new File(path);
        if (!file.exists()){
            throw new BadRequestException(path + "文件不存在");
        }
        try(FileInputStream fileInputStream = new FileInputStream(file) ;
            ByteArrayOutputStream out = new ByteArrayOutputStream() ) {
            byte[] b = new byte[1024];
            while (fileInputStream.read(b)!= -1) {
                out.write(b, 0, b.length);
            }
            return out;
        } catch (IOException e) {
            e.printStackTrace();
            throw new BadRequestException(path +"文件转ByteArrayOutputStream异常",e);
        }
    }

    /**
     * 压缩文件
     * @param tempPath 临时路径
     * @param function 转换函数
     * @param ts 参数
     * @param <T> 参数泛型
     * @return 输出流
     */
    @SafeVarargs
    public static<T> ByteArrayOutputStream zip(String tempPath , Function<T, Back<ByteArrayOutputStream>> function , T... ts){
        // 临时文件夹名
        String id = IdUtil.getSnowflakeId().toString();
        // zip入径
        String zipPath = tempPath + id + ".zip";
        // 临时文件夹入径
        String path = tempPath + id + "/";
        // 创建临时文件夹
        FileUtil.mkdirs(path);
        // 单个word入径
        String filePath ;
        try {
            for (T t : ts) {
                // 生成word
                Back<ByteArrayOutputStream> back = function.apply(t);
                // word入径
                filePath = path + back.getExtra().toString();
                // 将word保存到本地
                FileUtil.save(back.getData(),filePath);
            }
            // 压缩
            ZipUtil.zip(path,zipPath);
            // 生成文件流
            return  FileUtil.fileToByteArrayOutputStream(zipPath);
        }catch (RuntimeException e){
            log.error("导出失败",e);
            throw new BadRequestException("导出失败",e);
        }finally {
            // 删除文件夹与压缩文件
            cn.hutool.core.io.FileUtil.del(path);
            cn.hutool.core.io.FileUtil.del(zipPath);
        }
    }



}
